﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Xejen.Database.Entities;

namespace Xejen.Database.Dapper
{
    /// <summary>
    /// 提供Dapper仓储访问，允许指定泛型的实体类以及该实体类的泛型主键类型
    /// </summary>
    /// <typeparam name="TEntity">表示实体类类型</typeparam>
    /// <typeparam name="TPrimaryKey">表示实体类的主键类型</typeparam>
    /// <creator>marc</creator>
    public interface IRepository<TEntity, TPrimaryKey> : IRepository
    {
        #region Select/Get/Query

        /// <summary>
        /// Used to get a IQueryable that is used to retrieve entities from entire table.
        /// </summary>
        /// <returns>IQueryable to be used to select entities from database</returns>
        IQueryable<TEntity> GetAll(string sql);

        /// <summary>
        /// Used to get a IQueryable that is used to retrieve entities from entire table.
        /// </summary>
        /// <returns>IQueryable to be used to select entities from database</returns>
        Task<IQueryable<TEntity>> GetAllAsync(string sql);

        /// <summary>
        /// Used to get all entities.
        /// </summary>
        /// <returns>List of all entities</returns>
        List<TEntity> GetAllList(string sql);

        /// <summary>
        /// Used to get all entities.
        /// </summary>
        /// <returns>List of all entities</returns>
        Task<List<TEntity>> GetAllListAsync(string sql);

        /// <summary>
        /// Gets exactly one entity with given predicate.
        /// Throws exception if no entity or more than one entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        TEntity Single(string sql);

        /// <summary>
        /// Gets exactly one entity with given predicate.
        /// Throws exception if no entity or more than one entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        Task<TEntity> SingleAsync(string sql);

        /// <summary>
        /// 取唯一数据
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <returns></returns>
        TEntity SingleOrDefault(string sql);

        /// <summary>
        /// 取唯一数据
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <returns></returns>
        Task<TEntity> SingleOrDefaultAsync(string sql);

        /// <summary>
        /// Gets an entity with given primary key or null if not found.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <returns>Entity or null</returns>
        TEntity FirstOrDefault(string sql);

        /// <summary>
        /// Gets an entity with given primary key or null if not found.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <returns>Entity or null</returns>
        Task<TEntity> FirstOrDefaultAsync(string sql);

        #endregion

        #region Insert

        /// <summary>
        /// Inserts a new entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Inserted entity</param>
        TEntity Insert(string sql, TEntity entity);

        /// <summary>
        /// Inserts a new entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Inserted entity</param>
        Task<TEntity> InsertAsync(string sql, TEntity entity);

        /// <summary>
        /// Inserts a new entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entities">Inserted entity</param>
        int Insert(string sql, List<TEntity> entities);

        /// <summary>
        /// Inserts a new entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entities">Inserted entity</param>
        Task<int> InsertAsync(string sql, List<TEntity> entities);

        /// <summary>
        /// Inserts a new entity and gets it's Id.
        /// It may require to save current unit of work
        /// to be able to retrieve id.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Entity</param>
        /// <returns>Id of the entity</returns>
        TPrimaryKey InsertAndGetId(string sql, TEntity entity);

        /// <summary>
        /// Inserts a new entity and gets it's Id.
        /// It may require to save current unit of work
        /// to be able to retrieve id.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Entity</param>
        /// <returns>Id of the entity</returns>
        Task<TPrimaryKey> InsertAndGetIdAsync(string sql, TEntity entity);

        /// <summary>
        /// Inserts or updates given entity depending on Id's value.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Entity</param>
        TEntity InsertOrUpdate(string sql, TEntity entity);

        /// <summary>
        /// Inserts or updates given entity depending on Id's value.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Entity</param>
        Task<TEntity> InsertOrUpdateAsync(string sql, TEntity entity);

        /// <summary>
        /// Inserts or updates given entity depending on Id's value.
        /// Also returns Id of the entity.
        /// It may require to save current unit of work
        /// to be able to retrieve id.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Entity</param>
        /// <returns>Id of the entity</returns>
        TPrimaryKey InsertOrUpdateAndGetId(string sql, TEntity entity);

        /// <summary>
        /// Inserts or updates given entity depending on Id's value.
        /// Also returns Id of the entity.
        /// It may require to save current unit of work
        /// to be able to retrieve id.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Entity</param>
        /// <returns>Id of the entity</returns>
        Task<TPrimaryKey> InsertOrUpdateAndGetIdAsync(string sql, TEntity entity);

        #endregion

        #region Update

        /// <summary>
        /// Updates an existing entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Entity</param>
        TEntity Update(string sql, TEntity entity);

        /// <summary>
        /// Updates an existing entity. 
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Entity</param>
        Task<TEntity> UpdateAsync(string sql, TEntity entity);

        /// <summary>
        /// Updates an existing entity. 
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entities">Entity</param>
        Task<int> UpdateAsync(string sql, List<TEntity> entities);

        #endregion

        #region Delete

        /// <summary>
        /// Deletes an entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Entity to be deleted</param>
        void Delete(string sql, TEntity entity);

        /// <summary>
        /// Deletes an entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entity">Entity to be deleted</param>
        Task DeleteAsync(string sql, TEntity entity);

        /// <summary>
        /// Deletes an entity by primary key.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="id">Primary key of the entity</param>
        void Delete(string sql, TPrimaryKey id);

        /// <summary>
        /// Deletes an entity by primary key.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="id">Primary key of the entity</param>
        Task DeleteAsync(string sql, TPrimaryKey id);

        /// <summary>
        /// Deletes an entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entities">Entity to be deleted</param>
        int Delete(string sql, List<TEntity> entities);

        /// <summary>
        /// Deletes an entity.
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="entities">Entity to be deleted</param>
        Task<int> DeleteAsync(string sql, List<TEntity> entities);

        #endregion

        #region Aggregates

        #endregion
    }
}